	/**
 *    Copyright (C) 2009 Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */

#ifndef _CUBEFS_CORE_API_METADATA_MODEL_HPP
#define _CUBEFS_CORE_API_METADATA_MODEL_HPP

#include <cubefs/api/metadata/model.hpp>
#include <cubefs/api/metadata/page.hpp>
#include <cubefs/core/api/metadata/group.hpp>

#define CUBEFS_SOURCE "cubefs/core/api/metadata/group.hpp:" CUBEFS_AT

namespace cubefs { namespace api {

template <typename Interface>
class ModelMetadataImplT: public MetadataGroupImplT<Interface> {
	typedef ModelMetadataImplT<Interface> 		Me;
	typedef MetadataGroupImplT<Interface> 		Base;
public:

	ModelMetadataImplT(StringRef name, const MetadataList &content, Int code, ModelFactoryFn factory): Base(name, content), code_(code), factory_(factory), hash_(0) {
		Base::set_type() = Interface::MODEL;

	    for (Int c = 0; c < content.size(); c++)
	    {
	        if (content[c]->GetTypeCode() == Metadata::PAGE)
	        {
	            PageMetadata *page = static_cast<PageMetadata*> (content[c]);
	            hash_ = hash_ + page->Hash();
	            page_map_[page->Hash()] = page;
	        }
	        else {
	            //exception;
	        }
	    }
	}

	virtual ~ModelMetadataImplT() throw () {}

	virtual Int Hash() {
		return hash_;
	}

	virtual Int Code() {
		return code_;
	}

	virtual ModelFactoryFn Factory() {
		return factory_;
	}

	virtual PageMetadata* GetPageMetadata(Int hashCode) {
		PageMetadataMap::iterator i = page_map_.find(hashCode);
		if (i != page_map_.end()) {
			return i->second;
		}
		else {
			throw CubefsException(CUBEFS_SOURCE, "Unknown page type hash code");
		}
	}


	static void Init() {
	    AbstractType *type = new AbstractType(TypeNameFactory<Interface>::name(), MetadataGroup::MyType());
	    type_ = type;

	    type->AddOperation(new BasicOperation<Int (Me::*)()>(type, "Hash", &Me::Hash));
	    type->AddOperation(new BasicOperation<Int (Me::*)()>(type, "Code", &Me::Code));

	    type->AddOperation(new BasicOperation<Typed* (Me::*)(Int), PageMetadata* (Me::*)(Int)>(type, PageMetadata::MyType(), "GetPageMetadata", "hash", &Me::GetPageMetadata));
	}

    CUBEFS_DECLARE_REFLECTION;

private:

    PageMetadataMap     page_map_;
    ModelFactoryFn 		factory_;

    Int hash_;
    Int code_;
};

template <typename Interface>
Type* ModelMetadataImplT<Interface>::type_ 					= NULL;

typedef ModelMetadataImplT<ModelMetadata> 					ModelMetadataImpl;



}}

#undef CUBEFS_SOURCE
#endif
